package com.polaris.live.viewmodel.message

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.blankj.utilcode.util.StringUtils
import com.google.common.cache.CacheBuilder
import com.polaris.live.common.cacha.CacheUtil
import com.polaris.live.common.cacha.UserManager
import com.polaris.live.common.mvvm.viewmodel.BaseViewModel
import com.polaris.live.common.mvvm.viewmodel.SequentialLiveData
import com.polaris.live.common.network.getSuccessResult
import com.polaris.live.common.network.isSuccessAndValuable
import com.polaris.live.common.network.request
import com.polaris.live.common.network.state.ResultState
import com.polaris.live.common.network.state.paresException
import com.polaris.live.common.network.state.paresResult
import com.polaris.live.common.util.JsonUtils
import com.polaris.live.common.util.MutexCache
import com.polaris.live.im.db.database.AppDatabase
import com.polaris.live.im.db.entity.MessageEntity
import com.polaris.live.im.db.entity.SessionEntity
import com.polaris.live.im.manager.ImSessionManager
import com.polaris.live.im.sfs.COMMAND_SINGLE_MESSAGE
import com.polaris.live.im.sfs.COMMAND_STRANGER_MESSAGE
import com.polaris.live.im.sfs.COMMAND_SYSTEM_MESSAGE
import com.polaris.live.im.sfs.SYSTEM_USER_ID
import com.polaris.live.im.sfs.TYPE_MESSAGE_TEXT
import com.polaris.live.im.sfs.bean.chat.ReceiveSingleMessage
import com.polaris.live.im.sfs.bean.live.ext.UserBasicVo
import com.polaris.live.im.utils.MessageEntityUtils
import com.polaris.live.im.utils.toSelfSessionEntity
import com.polaris.live.im.utils.toSessionEntity
import com.polaris.live.net.userService
import com.polaris.live.resp.back_resp.CustomerMessageUnreadResp
import com.polaris.live.resp.back_resp.UserCustomerServiceResp
import com.polaris.live.resp.back_resp.toUserBasicVo
import com.polaris.live.translation.R
import com.polaris.live.widget.refresh.OnListListener
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import java.util.concurrent.TimeUnit

/**
 * 消息会话列表ViewModel
 *
 * @author Created by lucas on 2023/10/28 09:01
 * @since 1.0.0
 */
class MessageSessionViewModel : BaseViewModel(), OnListListener {

    companion object {

        private val mutexCache = MutexCache<Long, UserBasicVo> {
            CacheBuilder.newBuilder()
                .maximumSize(300)
                .expireAfterWrite(5, TimeUnit.MINUTES)
        }

        suspend fun getUserBasicVo(userId: Long): UserBasicVo? {
            return mutexCache.get(userId) {
                try {
                    userService.infoBasic(it.toString())
                } catch (_: Throwable) {
                    //如果请求失败这里重试一次
                    try {
                        userService.infoBasic(it.toString())
                    } catch (_: Throwable) {
                        null
                    }
                }?.getSuccessResult()?.firstOrNull()
            }
        }
    }

    val pageSize = 50  // 每页记录数

    val sessionLiveData = MutableLiveData<ResultState<List<SessionEntity>>>()
    val receiveLiveData = SequentialLiveData<SessionEntity>()

    val lastStrangerMessageLiveData = MutableLiveData<Pair<UserBasicVo?, MessageEntity>?>()
    private var lastStrangerMessageJob: Job? = null

    var sessionCommand = COMMAND_SYSTEM_MESSAGE
    private fun isSystemMessage(): Boolean {
        return sessionCommand == COMMAND_SYSTEM_MESSAGE
    }

    override fun onRefresh() {
        viewModelScope.launch {
            try {
                val sessions = findSessionEntities()
                val systemSessions = if (isSystemMessage()) {
                    listOf(genSystemSession(), genStrangerSession())
                } else {
                    emptyList()
                }
                val finalSessions = systemSessions + sessions
                sessionLiveData.paresResult(finalSessions)
            } catch (t: Throwable) {
                sessionLiveData.paresException(t)

                t.printStackTrace()
            }
        }
    }

    private suspend fun handleUserBasic(sessions: List<SessionEntity>) {
        val fillSessions = sessions.filter { it.userJson == null }
        if (fillSessions.isEmpty()) {
            return
        }
        val fillSessionsMap = fillSessions.associateBy { it.otherId }

        getUserBasic(fillSessions.map { it.otherId }).forEach {
            fillSessionsMap[it.userId]?.apply {

                val userJson = JsonUtils.toJson(it)
                updateSessionUser(this, userJson)

                updateUserBasic(it)
            }
        }
    }

    private suspend fun getUserBasic(userIds: List<Long>): List<UserBasicVo> {
        val userBasicResp = userService.infoBasic(userIds.joinToString { it.toString() })
        if (!userBasicResp.isSuccessAndValuable()) {
            return emptyList()
        }

        return userBasicResp.result ?: emptyList()
    }

    override fun onLoadMore(pageIndex: Int) {
        viewModelScope.launch {
            try {
                val sessions = findSessionEntities(pageIndex)

                sessionLiveData.paresResult(sessions)
            } catch (t: Throwable) {
                sessionLiveData.paresException(t)
                t.printStackTrace()
            }
        }
    }

    private suspend fun findSessionEntities(pageIndex: Int = 0): List<SessionEntity> {
        val sessions = ImSessionManager.withSession {
            AppDatabase.instance.sessionListDao().let {
                if (isSystemMessage()) {
                    //查找非陌生人消息
                    it.getSessions(UserManager.getUserId(), pageSize, getOffset(pageIndex))
                } else {
                    //查询陌生人消息
                    it.getSessionsByStranger(
                        UserManager.getUserId(),
                        pageSize,
                        getOffset(pageIndex)
                    )
                }
            }
        }
        //可能因为某些原因导致用户信息为空，需要重新获取
        handleUserBasic(sessions)
        return sessions
    }

    private fun getOffset(pageIndex: Int): Int {
        return pageIndex * pageSize
    }

    //生成系统消息会话bean
    private suspend fun genSystemSession(): SessionEntity {
        val systemUnreadCount = AppDatabase.instance.sessionListDao()
            .getUnreadCountByOtherId(UserManager.getUserId(), SYSTEM_USER_ID)?.unreadCount ?: 0

        val lastEntity = AppDatabase.instance.messageDao()
            .findLastSystemMessageByUniqueId(UserManager.getUserId(), SYSTEM_USER_ID)
        return if (lastEntity != null) {
            SessionEntity(
                command = COMMAND_SYSTEM_MESSAGE,
                userId = UserManager.getUserId(),
                otherId = SYSTEM_USER_ID,
                senderId = SYSTEM_USER_ID,
                type = lastEntity.type,
                content = lastEntity.content,
                timestamp = lastEntity.timestamp,
                seqId = lastEntity.seqId,
                ext = lastEntity.ext,
                payload = lastEntity.payload,
                unreadCount = systemUnreadCount
            )
        } else {
            SessionEntity(
                command = COMMAND_SYSTEM_MESSAGE,
                userId = UserManager.getUserId(),
                otherId = SYSTEM_USER_ID,
                senderId = SYSTEM_USER_ID,
                unreadCount = systemUnreadCount
            )
        }
    }

    private suspend fun genStrangerSession(): SessionEntity {
        val strangerUnreadCount = ImSessionManager.getStrangerUnreadCount()

        val lastEntity = AppDatabase.instance.messageDao()
            .findLastStrangerMessageByUniqueId(UserManager.getUserId())

        return if (lastEntity != null) {
            val userBasic = getUserBasic(listOf(lastEntity.otherId)).firstOrNull()
            val content =
                MessageEntityUtils.genStrangerContent(
                    userBasic,
                    lastEntity.translateContent,
                    lastEntity.content
                )

            SessionEntity(
                command = COMMAND_STRANGER_MESSAGE,
                userId = UserManager.getUserId(),
                otherId = lastEntity.otherId,
                senderId = lastEntity.sender,
                type = lastEntity.type,
                content = content,
                timestamp = lastEntity.timestamp,
                seqId = lastEntity.seqId,
                ext = lastEntity.ext,
                payload = lastEntity.payload,
                unreadCount = strangerUnreadCount
            )
        } else {
            SessionEntity(
                command = COMMAND_STRANGER_MESSAGE,
                userId = UserManager.getUserId(),
                otherId = SYSTEM_USER_ID,
                senderId = SYSTEM_USER_ID,
                unreadCount = strangerUnreadCount
            )
        }
    }

    fun getLastStrangerMessage() {
        lastStrangerMessageJob?.cancel()
        lastStrangerMessageJob = viewModelScope.launch {
            try {
                val lastEntity = AppDatabase.instance.messageDao()
                    .findLastStrangerMessageByUniqueId(UserManager.getUserId())

                if (lastEntity != null) {
                    val userBasic = getUserBasic(listOf(lastEntity.otherId)).firstOrNull()
                    lastStrangerMessageLiveData.value = userBasic to lastEntity
                } else {
                    lastStrangerMessageLiveData.value = null
                }
            } finally {
                if (lastStrangerMessageJob == coroutineContext[Job]) {
                    lastStrangerMessageJob = null
                }
            }
        }
    }

    fun getReceiveInfoBasic(message: ReceiveSingleMessage, lastSessionEntity: SessionEntity?) {
        val lastUpdateUserTime = lastSessionEntity?.getLastUpdateUserTime()
        val lastUserBasic = lastSessionEntity?.userBasic
        val needUpdateUser = lastUpdateUserTime == null
                || (CacheUtil.getServerTime() - lastUpdateUserTime) > 15 * 1000
                || lastUserBasic == null

        if (!needUpdateUser && lastUserBasic != null && lastSessionEntity.userJson != null) {
            invokeReceiveInfoBasic(message, lastUserBasic, lastSessionEntity.userJson, false)
        } else {
            viewModelScope.launch {
                //使用锁缓存，保证顺序请求
                val userBasic = getUserBasicVo(message.getOtherId())

                val userJson = userBasic?.let { JsonUtils.toJson(userBasic) }

                (userJson ?: lastSessionEntity?.userJson)?.also {
                    val ub = userBasic
                        ?: lastUserBasic
                        ?: JsonUtils.fromJson<UserBasicVo>(it)
                        ?: return@also

                    invokeReceiveInfoBasic(message, ub, it, userBasic != null)
                }
            }
        }
    }

    private fun invokeReceiveInfoBasic(
        message: ReceiveSingleMessage,
        userBasic: UserBasicVo,
        userJson: String,
        needUpdateUser: Boolean
    ) {
        val sessionEntity = message.toSessionEntity(
            userJson,
            message.newSessionEntity?.unreadCount,
            message.newSessionEntity?.strangerUnreadCount
        ).apply {
            updateUserBasic(userBasic)
        }

        if (needUpdateUser) {
            updateSessionUser(sessionEntity, userJson)
        }

        receiveLiveData.setValue(sessionEntity)
    }

    fun getSendInfoBasic(message: MessageEntity) {
        viewModelScope.launch {
            val userBasic = getUserBasicVo(message.recipient)
            val userJson = JsonUtils.toJson(userBasic)
            val sessionEntity = message.toSelfSessionEntity(userJson).apply {
                updateUserBasic(userBasic)
            }
            updateSessionUser(sessionEntity, userJson)

            receiveLiveData.setValue(sessionEntity)
        }
    }

    //更新会话用户信息
    private fun updateSessionUser(sessionEntity: SessionEntity, userJson: String) {
        ImSessionManager.launchSession {
            AppDatabase.instance.sessionListDao()
                .updateSessionUserByOtherId(
                    UserManager.getUserId(),
                    sessionEntity.otherId,
                    userJson
                )
        }
    }

    //清除会话
    fun clearSession(item: SessionEntity) {
        ImSessionManager.launchSession {
            if (item.command == COMMAND_STRANGER_MESSAGE) {
                ImSessionManager.clearStrangerAllUnreadCount()
            } else {
                ImSessionManager.deleteSession(item.otherId)
            }
        }
    }

    //进来的时候先清除陌生人未读数，外面的总数
    fun clearStrangerUnreadCount() {
        ImSessionManager.clearStrangerUnreadCount()
    }

    //清除所有陌生人未读数，单个的
    fun clearStrangerAllUnreadCount() {
        if (sessionCommand != COMMAND_STRANGER_MESSAGE) {
            return
        }
        ImSessionManager.launchSession {
            ImSessionManager.clearStrangerAllUnreadCount()
        }
    }


    //获取是否有客服
    val customerLiveData = MutableLiveData<ResultState<UserCustomerServiceResp>>()
    fun getCustomerService() {
        request({ userService.customerService() }, customerLiveData)
    }

    /**
     * 客服红点消息
     */
    val mCustomerReadLiveData = MutableLiveData<ResultState<CustomerMessageUnreadResp>>()
    fun getCustomerRead() {
        request({ userService.customerServiceUnread() }, mCustomerReadLiveData)
    }

    /**
     * 获取主播的基础信息
     */
    var infoLiveData = MutableLiveData<SessionEntity>()
    fun getInfoAnchor(id: Long) {
        request({ userService.getInfoOther(id, UserManager.BASIC_INFORMATION) }, {
            val sessionEntity = SessionEntity(
                command = COMMAND_SINGLE_MESSAGE,
                userId = UserManager.getUserId(),
                otherId = it.userId,
                type = TYPE_MESSAGE_TEXT,
                content = StringUtils.getString(R.string.like_anchor_go_message),
                userJson = JsonUtils.toJson(it.toUserBasicVo()),
            )
            infoLiveData.value = sessionEntity
        })
    }
}